# -*- coding: utf-8 -*-
import logging
from datetime import datetime, timedelta

from sqlalchemy import func

from common import orm
from common.utils.db import get_count
from common.account.db.account import get_account
from common.missed_vips.model.missed_vips import (
    MissedVips, CALLBACK_STATUS, BackVips, ActiveTop, ActiveVips, VIP_TYPE)
from common.utils.tz import local_now, get_utc_date
from common.utils.decorator import sql_wrapper
from common.stats.helper import (get_orderby, parse_query_dct,
                                 generate_filter, list_object, paginate)
from common.stats import MG_BIGBANG_COLL as mg

_LOGGER = logging.getLogger(__name__)


@sql_wrapper
def batch_insert_missed_vips(data, created_at=None):
    if not data:
        return
    if created_at is None:
        created_at = local_now().strftime('%Y-%m-%d')
    engine = orm.get_engine(None, None, None)
    for i, d in enumerate(data):
        d['status'] = CALLBACK_STATUS.UNCALLED
        d['created_at'] = created_at
        d['updated_at'] = datetime.utcnow()
        d['rank'] = i + 1
    engine.execute(MissedVips.__table__.insert(), data)


@sql_wrapper
def batch_insert_back_vips(data):
    if not data:
        return
    engine = orm.get_engine(None, None, None)
    engine.execute(BackVips.__table__.insert(), data)


@sql_wrapper
def batch_insert_active_top(data, created_at=None):
    if not data:
        return
    if created_at is None:
        created_at = local_now().strftime('%Y-%m-%d')
    vip_datas = []
    vips = set()
    engine = orm.get_engine(None, None, None)
    for d in data:
        d['created_at'] = created_at
        d['updated_at'] = datetime.utcnow()
        uid = d['uid']
        if uid in vips:
            continue
        else:
            vips.add(uid)
        vip = ActiveVips.query.filter(ActiveVips.id == uid).first()
        if not vip:
            account = get_account(uid)
            vip_data = {
                'id': uid,
                'nick_name': account.nick_name,
                'phone': account.phone[2:],
                'created_time': account.created_at,
            }
            vip_datas.append(vip_data)
    engine.execute(ActiveTop.__table__.insert(), data)
    engine.execute(ActiveVips.__table__.insert(), vip_datas)


@sql_wrapper
def batch_update_active_vip_status(uids, status):
    # 1：回访， 2：专属客服
    uids = set(uids)
    for uid in uids:
        vip = ActiveVips.query.with_for_update().filter(
            ActiveVips.id == uid).first()
        if not vip:
            _LOGGER.error('active vip %s not exist!', uid)
            continue
        if status & 1:
            vip.visit_time = datetime.utcnow()
        else:
            vip.visit_time = None
        if status & 2:
            vip.add_time = datetime.utcnow()
        else:
            vip.add_time = None
        vip.save()


@sql_wrapper
def batch_update_missed_vips(ids, status):
    for id in ids:
        vip = MissedVips.query.with_for_update().filter(
            MissedVips.id == id).first()
        if vip:
            vip.status = vip.status | status if status != 0 else 0
            vip.save()


@sql_wrapper
def list_active_vips(query_dct):
    status = query_dct.pop('status', None)
    query = orm.session.query(ActiveTop, ActiveVips).join(
        ActiveVips, ActiveTop.uid == ActiveVips.id)
    if status is not None:
        status = int(status)
        if status & 1:  # 已回访
            query = query.filter(ActiveVips.visit_time != None)
        else:
            query = query.filter(ActiveVips.visit_time == None)
        if status & 2:  # 已添加专属
            query = query.filter(ActiveVips.add_time != None)
        else:
            query = query.filter(ActiveVips.add_time == None)
    user_filter = {}
    for k in 'add_time', 'visit_time':
        if k in query_dct:
            user_filter[k] = query_dct.pop(k)
    if user_filter:
        user_filter = parse_query_dct(user_filter, ActiveVips)
        query = query.filter(generate_filter(user_filter, ActiveVips))
    query_dct = parse_query_dct(query_dct, ActiveTop)
    query = query.filter(generate_filter(query_dct, ActiveTop))
    total_count = get_count(query)
    orderby = get_orderby(query_dct.get('$orderby'), ActiveTop)
    if orderby is not None:
        query = query.order_by(orderby)
    return query.all(), total_count


@sql_wrapper
def list_back_vips(query_dct):
    return list_object(query_dct, BackVips)


@sql_wrapper
def list_missed_vips(query_dct):
    status = query_dct.pop('status', None)
    coupon_level = query_dct.pop('coupon_level', None)
    query_dct = parse_query_dct(query_dct, MissedVips)
    query = MissedVips.query
    if status is not None:
        status = int(status)
        if status == 0:
            query = query.filter(MissedVips.status == 0)
        else:
            query = query.filter(MissedVips.status.op('&')(status) > 0)
    if coupon_level is not None:
        coupon_level = int(coupon_level)
        user_type = query_dct.get('user_type')
        if user_type:
            user_type = int(user_type)
        if coupon_level == 1:
            l = 11 if user_type else 1000
            query = query.filter(MissedVips.recharge_amount < l)
        elif coupon_level == 2:
            if user_type:
                l, h = 11, 51
            else:
                l, h = 1000, 4000
            query = query.filter(MissedVips.recharge_amount >= l).filter(
                MissedVips.recharge_amount < h)
        elif coupon_level == 3:
            h = 51 if user_type else 4000
            query = query.filter(MissedVips.recharge_amount >= h)
    query = query.filter(generate_filter(query_dct, MissedVips))
    total_count = get_count(query)
    orderby = get_orderby(query_dct.get('$orderby'), MissedVips)
    if orderby is not None:
        query = query.order_by(orderby)
    query = paginate(query, query_dct)
    return query.all(), total_count


@sql_wrapper
def calc_back_info(day):
    resp = {
        'new': {"stay_rate": 0, "recharge_rate": 0, "back_rate": 0},
        3: {"stay_rate": 0, "recharge_rate": 0, "back_rate": 0},
        7: {"stay_rate": 0, "recharge_rate": 0, "back_rate": 0},
        14: {"stay_rate": 0, "recharge_rate": 0, "back_rate": 0}
    }
    back_info = {}
    today = get_utc_date()
    yesterday = today - timedelta(days=1)
    if day is None:
        day = yesterday.strftime('%Y-%m-%d')

    for d in resp.keys():
        query = MissedVips.query.filter(MissedVips.created_at == day)
        if d == 'new':
            query = query.filter(MissedVips.user_type == 1)
        else:
            query = query.filter(MissedVips.lost_days == d).filter(
                MissedVips.user_type == 0)
        items = query.all()
        uids = {k.uid: k for k in items}
        if not uids:
            continue
        # 回流率
        # 付费率
        users = mg.user_stats.find({"_id": {"$in": uids.keys()},
                                    "updated_at": {"$gte": get_utc_date(day)}})
        back_count = recharge_count = 0
        for user in users:
            uid = user['_id']
            if uids[uid].status & CALLBACK_STATUS.BACK == 0:
                uids[uid].status |= CALLBACK_STATUS.BACK
            back_count += 1
            back_info[uid] = {
                "recharge": 0,
                "used_coupon": 0,
                "updated_at": user['updated_at']
            }
            x = mg.daily_stats.aggregate([
                {"$match": {"$and": [
                    {"user_id": uid},
                    {"updated_at": {"$gte": get_utc_date(day)}}
                ]}},
                {"$group": {"_id": None,
                            "recharge": {"$sum": "$recharge.total"}}}
            ])
            x = x.next() if x.alive else {}
            if x.get('recharge', 0) > 0:
                back_info[uid]["recharge"] = x.get('recharge')
                recharge_count += 1

        orm.session.commit()
        # 留存率
        if back_count > 0:
            resp[d]['back_rate'] = back_count * 1.0 / len(uids)
            resp[d]['recharge_rate'] = recharge_count * 1.0 / back_count
            t = mg.user_stats.aggregate([
                {"$match": {"$and": [
                    {"_id": {"$in": uids.keys()}},
                    {"updated_at": {"$gte": today}}
                ]}},
                {"$group": {"_id": None, "count": {"$sum": 1}}}
            ])
            t = t.next() if t.alive else {}
            resp[d]['stay_rate'] = t.get('count', 0) * 1.0 / back_count

    return resp, back_info
